#include "httpserver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include "tools.h"
/*========================================================== 
    函数名 ：   StartHttpServer
    功能 ：		开启http服务
    算法实现 ： <可选项> 
    参数说明 ： int     nServerPort     [in]    服务监听端口号
    返回值说明：-1 服务启动失败（端口绑定失败）0 成功，服务启动成功，会阻塞线程，此方法不会退出
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
int StartHttpServer(int nServerPort)
{
    // 创建服务器套接字
    int nServerSocket = CreateSocket(AF_INET, SOCK_STREAM,0);
    if(-1 == nServerPort)
    {
        TRACE_DEBUG("create socket failed!");
        return -1;
    }

    // 设置服务器地址
    struct sockaddr_in tServerAddr;
    memset(&tServerAddr, 0, sizeof(tServerAddr));
    tServerAddr.sin_family = AF_INET;
    tServerAddr.sin_port = htons(nServerPort);
    tServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 绑定套接字到本地地址
    int nBindRet = bind(nServerSocket, (struct sockaddr *) &tServerAddr, sizeof(tServerAddr));
    if (-1 == nBindRet) 
    {
        perror("Bind failed");
        TRACE_DEBUG("%s",perror("bind failed"));
        return -1;
    }

    // 监听端口
    int nListenRet = listen(nServerSocket, SOMAXCONN);
    if (-1 == nListenRet) 
    {
        perror("Listen failed");
        TRACE_DEBUG("%s",perror("listen failed!"));
        return -1;
    }
    TRACE_DEBUG("Server started. Listening on port %d...", nServerPort);

    // 循环检测是否有新客户端连接
    while (1) 
    {
        // 接收连接请求
        struct sockaddr_in tClientAddress;
        socklen_t nClientAddressLen = sizeof(tClientAddress);
        int nClientSocket = accept(nServerSocket, (struct sockaddr *) &tClientAddress, &nClientAddressLen);
        if (nClientSocket == -1) 
        {
            TRACE_DEBUG("%s",perror("accept failed!"));
            continue;
        }
        TRACE_DEBUG("new client socket fd = %d",nClientSocket);

        // 需要发送
        PHttpClientInfo ptClientInfo = (PHttpClientInfo)malloc(sizeof(HttpClientInfo));
        strncpy(ptClientInfo->achHost,inet_ntoa(tClientAddress.sin_addr),IPV4_BUF_LEN);
        ptClientInfo->nSocket = nClientSocket;
        TRACE_DEBUG("Client connected. IP address: %s", ptClientInfo->achHost);
        
        // 处理客户端连接
        pthread_t tClientThread;
        pthread_create(&tClientThread, NULL, CBHttpClientHandle, (void *) ptClientInfo);
        pthread_detach(tClientThread);
    }

    // 关闭服务器套接字
    close(nServerSocket);
    return 0;
}

/*========================================================== 
    函数名 ：   CBHttpClientHandle
    功能 ：		处理http连接函数
    算法实现 ： <可选项> 
    参数说明 ： void*     pArg     [in]    HttpClientInfo结构体，包含http连接信息,需要在函数体释放
    返回值说明：
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
void CBHttpClientHandle(void *pArg)
{
    // 参数有效判断
    if(NULL == pArg)
    {
        TRACE_DEBUG("invalid argument ");
        return ;
    }
    // 转换为客户端连接参数,并释放参数
    HttpClientInfo tClientInfo = *((PHttpClientInfo)(pArg));
    free((PHttpClientInfo)pArg);
    TRACE_DEBUG("handle host : %s socket : %d",tClientInfo.achHost,tClientInfo.nSocket);

    // 读取客户端发送的HTTP请求
    char achBuffer[BUFFER_SIZE];
    ssize_t nHttpReqSize = recv(tClientInfo.nSocket, achBuffer, BUFFER_SIZE, 0);
    if (-1 == nHttpReqSize) // 如果读取数据失败，关闭套接字
    {
        TRACE_DEBUG("%s",perror("Receive failed !"));
        close(tClientInfo.nSocket);
        return;
    }    
    achBuffer[nHttpReqSize] = '\0';
    TRACE_DEBUG("%s",achBuffer);

    // 处理HTTP请求
    HanldeHttpReq(achBuffer, &tClientInfo);

    // 关闭客户端套接字
    close(tClientInfo.nSocket);
    return ;
}

/*========================================================== 
    函数名 ：   HanldeHttpReq
    功能 ：		处理http请求
    算法实现 ： <可选项> 
    参数说明 ： char*     paBuffer     [in]    http客户端请求数据
               PHttpClientInfo   info  [in]    HttpClientInfo结构体，包含http连接信息,需要在函数体释放
    返回值说明：
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
void HanldeHttpReq(const char *paBuffer,const PHttpClientInfo info)
{
    // http请求缓冲区
    char achMethod[BUFFER_SIZE];
    char achUri[BUFFER_SIZE];
    char achHttpVersion[BUFFER_SIZE];

    // 解析HTTP请求
    sscanf(paBuffer, "%s %s %s", achMethod, achUri, achHttpVersion);
    TRACE_DEBUG("method : %s\n uri : %s\n version : %s\n",achMethod,achUri,achHttpVersion);

    // 根据请求方式解析请求数据
    if(0 == strcmp(achMethod , "POST"))
    {
        // 处理post请求
        ParsePostReq(paBuffer,info);
    }
    else
    {
        // 不支持的HTTP方法，返回405 Method Not Allowed
        char *paRep = "HTTP/1.1 405 Method Not Allowed\r\n"
                        "Content-Length: 0\r\n"
                        "\r\n";
        send(info->nSocket, paRep, strlen(paRep), 0);
    }
    return ;  
}

/*========================================================== 
    函数名 ：   ParsePostReq
    功能 ：		处理post请求
    算法实现 ： <可选项> 
    参数说明 ： char*     paBuffer     [in]    http客户端请求数据
               PHttpClientInfo   info  [in]    HttpClientInfo结构体，包含http连接信息,需要在函数体释放
    返回值说明：
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
void ParsePostReq(const char *paBuffer,const PHttpClientInfo info)
{
    // 查找Content-Length头部
    char *paHeader = strstr(paBuffer, "Content-Length");
    if (NULL == paHeader) 
    {
        // 没有Content-Length头部，不处理POST请求体
        TRACE_DEBUG("not found Content-Length");
        return;
    }

    // 解析Content-Length头部的值
    int nContentLength = atoi(paHeader);

    // 查找请求体
    char *paBody = strstr(request, "\r\n");
    if (NULL == paBody) 
    {
        // 没有请求体
        TRACE_DEBUG("not found body");
        return;
    }
    paBody +=  2;
    TRACE_DEBUG("POST request body: %.*s",nContentLength, paBody);

    // 解析body数据
    HttpPostBodyInfo tBodyInfo;
    int nParseBodyRet = ParsePostBody(paBody,&tBodyInfo);
    if(0 != nParseBodyRet)
    {
        TRACE_DEBUG("parse post body failed");
        // 参数错误，返回406 Not Acceptable
        char *paRep = "HTTP/1.1 406 Not Acceptable\r\n"
                        "Content-Length: 0\r\n"
                        "\r\n";
        send(info->nSocket, paRep, strlen(paRep), 0);
        return ;
    }

    // 判断是否为重复发送的请求


    // 构造响应消息
    char *paResponse = "HTTP/1.1 200 OK\r\n"
                    "Content-Type: text/plain\r\n"
                    "\r\n"
                    "Hello, World!";

    // 发送响应
    send(client_socket, paResponse, strlen(paResponse), 0);
}

/*========================================================== 
    函数名 ：   ParsePostBody
    功能 ：		解析post body数据
    算法实现 ： <可选项> 
    参数说明 ： char*     paBody     [in]      http客户端请求body
               PHttpPostBodyInfo   info  [out] 传出解析post请求body
    返回值说明：
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
int ParsePostBody(const char *paBody,PHttpPostBodyInfo info)
{

}